package com.dituhui.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.dituhui.gps.local.GPSHandler;
import com.dituhui.tool.gis.CoordConverter;
import com.dituhui.tool.gis.Point;
import com.dituhui.tool.gis.Region;
import com.dituhui.tool.io.Constants;
import com.dituhui.tool.io.FileTool;
import com.dituhui.tool.io.HttpTool;
import com.dituhui.tool.io.KafkaTool;
import com.dituhui.tool.util.StringUtil;
import com.dituhui.web.util.UserInfoUtil;
import com.dituhui.web.vo.UserInfo;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 支持微信客户端的GPS网关服务
 * 
 * @author liweigu
 * 
 */
public class Weixin extends HttpServlet {
	static String kafkaUrl;
	static String kafkaTopic = "GPS";
	private String logFilePath;
	private static final Logger LOGGER = Logger.getLogger(Weixin.class);

	public void init() throws ServletException {
		kafkaUrl = Constants.getValue("kafkaUrl");
		LOGGER.info("kafkaUrl=" + kafkaUrl);
		this.logFilePath = Constants.getValue("logFilePath", "web_config.properties");
		LOGGER.info("logFilePath=" + this.logFilePath);
	}

	// 1)上传坐标（可以不传cmd）（日期要设置为当天才会写入Redis）
	// http://ip:port/weixin?a=test&g=106.0^30.0^1^2017-02-06 11:34:00
	// 2)记录日志
	// http://ip:port/weixin?a=test&cmd=log&log=abc...
	// 3)微信登陆（废弃）
	// http://ip:port/weixin?a=test&cmd=login
	// 4)获取工作区
	// http://ip:port/weixin?a=test&cmd=getareas&coord=x,y
	// 5)微信登陆到组（可以同时返回个人信息）
	// http://ip:port/weixin?a=test&cmd=logingroup&phone=&groupid=
	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		String accountId = request.getParameter("a");
		String command = request.getParameter("cmd");
		response.setCharacterEncoding("UTF-8");
		PrintWriter out = response.getWriter();
		if ("log".equals(command)) {
			// 记录日志
			String logData = request.getParameter("log");
			if (logData != null && logData.length() > 0) {
				String line = "accountId=" + accountId + ",log=" + logData;
				LOGGER.debug("记录日志：" + line);
				ArrayList<String> lines = new ArrayList<String>();
				lines.add(line);
				boolean append = true;
				FileTool.writeFile(this.logFilePath, lines, append);
			}
			out.print("logged");
		} else if ("login".equals(command)) {
			// 微信登陆
			UserInfo userInfo = UserInfoUtil.getUserInfoByPhone(accountId);
			JSONObject jsonObject = JSONObject.fromObject(userInfo);
			String result = jsonObject.toString();
			out.print(result);
		} else if ("logingroup".equals(command)) {
			// 微信登陆
			String phone = request.getParameter("phone");
			String groupId = request.getParameter("groupid");
			String group = this.loginToGroup(accountId, phone, groupId);
			out.print(group);
		} else if ("getareas".equals(command)) {
			// 坐标检测
			String coord = request.getParameter("coord");
			String areas = this.getAreas(accountId);
			if (areas != null) {
				JSONObject jsonObject = JSONObject.fromObject(areas);
				boolean success = jsonObject.getBoolean("success");
				if (success) {
					JSONObject result = jsonObject.getJSONObject("result");
					JSONArray records = result.getJSONArray("records");
					for (int i = 0; i < records.size(); i++) {
						JSONObject record = records.getJSONObject(i);
						JSONArray point2Ds = record.getJSONArray("point2Ds");
						List<Point> points = new ArrayList<Point>();
						for (int j = 0; j < point2Ds.size(); j++) {
							JSONObject point = point2Ds.getJSONObject(j);
							double x = point.getDouble("x");
							double y = point.getDouble("y");
							Point p = new Point(x, y);
							if (x > 360) {
								// 墨卡托转经纬度
								CoordConverter.mercatorToLngLat(p);
								point.element("x", StringUtil.formatDouble(p.x, StringUtil.SixFractionFormat));
								point.element("y", StringUtil.formatDouble(p.y, StringUtil.SixFractionFormat));
							}
							points.add(p);
						}
						Region region = new Region(points);
						String[] arr = coord.split(StringUtil.COMMA);
						double x = Double.parseDouble(arr[0]);
						double y = Double.parseDouble(arr[1]);
						Point point = new Point(x, y);
						boolean isContain = region.contains(point);
						record.accumulate("isContain", isContain);
					}
				}
				// LOGGER.info("jsonObject.toString() = " + jsonObject.toString());
				out.print(jsonObject.toString());
			}
		} else {
			// 上传坐标
			if (accountId == null) {
				String message = "参数非法，应传入accountId";
				LOGGER.info(message);
				out.print(message);
			} else {
				String gpsData = request.getParameter("g");
				// System.out.println("gpsData = " + gpsData);
				if (gpsData != null) {
					// String message = x + StringUtil.AngularBracket + y + StringUtil.AngularBracket + accuracy + StringUtil.AngularBracket + time +
					// StringUtil.AngularBracket + groupId + StringUtil.AngularBracket + phone;
					List<String> messages = new ArrayList<String>();
					// 上传多个坐标时，以DoubleUnderline作为分隔符；每个坐标的属性以AngularBracket作为分隔符。
					if (gpsData != null && gpsData.contains(StringUtil.DoubleUnderline)) {
						String[] arr = gpsData.split(StringUtil.DoubleUnderline);
						for (String s : arr) {
							messages.add(s);
						}
						LOGGER.info("reuploaded gpsData=" + gpsData);
					} else if (gpsData != null && gpsData.contains(StringUtil.AngularBracket)) {
						messages.add(gpsData);
					}

					if (messages.size() > 0) {
						for (String message : messages) {
							HashMap<String, String> data = new HashMap<String, String>();
							data.put(accountId, message);
							KafkaTool.produce(kafkaUrl, kafkaTopic, data);
							LOGGER.debug("after KafkaTool.produce()");
						}
						out.print("上传" + messages.size() + "条坐标成功.a=" + accountId);
					} else {
						long t = System.currentTimeMillis();
						LOGGER.info("参数非法.a=" + accountId + ",g=" + gpsData + ",t=" + t);
						out.print("参数非法,t=" + t);
					}
				} else {
					long t = System.currentTimeMillis();
					LOGGER.info("参数非法.a=" + accountId + ",g=" + gpsData + ",t=" + t);
					out.print("参数非法. command=" + command + ",t=" + t);
				}
			}
		}
		out.flush();
		out.close();
	}

	private String getAreas(String accountId) {
		String areas = null;

		String dataset_name = null;
		List<UserInfo> userInfos = UserInfoUtil.getUserInfos();
		for (UserInfo userInfo : userInfos) {
			if (accountId.equals(userInfo.getName())) {
				dataset_name = userInfo.getRegionDataset();
				break;
			}
		}
		if (dataset_name != null) {
			// TODO: 接口是否合法？
			String path = "http://dz.dituhui.com/datacenter/region";
			String param = "command=query&start=1&view_bounds=&limit=9999&dataset_name=" + dataset_name
					+ "&includes=point2ds,center,region_name,region_code&project_name=DTH";
			try {
				areas = HttpTool.getContentByGET(path, param);
				// System.out.println("areas=" + areas);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return areas;
	}

	private String loginToGroup(String accountId, String phone, String groupId) {
		String group = "";

		try {
			accountId = URLDecoder.decode(accountId, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			LOGGER.warn("URLDecoder.decode发生异常。accountId=" + accountId);
		}

		List<String> groups = UserInfoUtil.getGroups();
		for (String s : groups) {
			if (s != null && s.length() > 0) {
				JSONObject jsonObject = JSONObject.fromObject(s);
				JSONObject groupJSON = jsonObject.getJSONObject("group");
				String uuid = groupJSON.getString("uuid");
				// 匹配groupId
				if (groupId.equals(uuid)) {
					// 当前用户
					UserInfo currentUserInfo = UserInfoUtil.getUserInfoByPhone(phone);
					jsonObject.accumulate("userInfo", currentUserInfo);

					String visit = null;
					if (groupJSON.containsKey("visit")) {
						visit = groupJSON.getString("visit");
					}
					if ("open".equals(visit)) {
						// "open"代表任何人访问都是管理者，不校验身份
						jsonObject.accumulate("role", "manager");
						group = jsonObject.toString();
						// TODO: 支持多个所属分组
					} else {
						JSONObject manager = jsonObject.getJSONObject("manager");
						String managerPhone = manager.getString("phone");
						String managerName = manager.getString("name");
						// 匹配phone和name
						if (phone.equals(managerPhone) && accountId.equals(managerName)) {
							// 访问者是管理员身份
							jsonObject.accumulate("role", "admin");
							group = jsonObject.toString();
							// TODO: 支持多个所属分组
							break;
						} else {
							JSONArray admins = jsonObject.getJSONArray("admins");
							for (int i = 0; i < admins.size(); i++) {
								JSONObject admin = admins.getJSONObject(i);
								String adminPhone = admin.getString("phone");
								String adminName = admin.getString("name");
								// 匹配phone和name
								if (phone.equals(adminPhone) && accountId.equals(adminName)) {
									// 访问者是管理者身份
									jsonObject.accumulate("role", "admin");
									group = jsonObject.toString();
									break;
								}
							}
							if (group == null || group.length() == 0) {
								JSONArray userInfos = jsonObject.getJSONArray("userInfos");
								for (int i = 0; i < userInfos.size(); i++) {
									JSONObject userInfo = userInfos.getJSONObject(i);
									String userPhone = userInfo.getString("phone");
									String userName = userInfo.getString("name");
									// 匹配phone和name
									if (phone.equals(userPhone) && accountId.equals(userName)) {
										// 访问者是使用者身份
										jsonObject.accumulate("role", "user");
										group = jsonObject.toString();
										break;
									}
								}
							}
							if (group != null && group.length() > 0) {
								// TODO: 支持多个所属分组
								break;
							}
						}
					}
				}
			}
		}

		return group;
	}
}
